/*
 * Created on 2007-11-14
 *
 * TODO 
 */
package jacky.lanlan.song.util.sp;

import jacky.lanlan.song.closure.Judgment;

/**
 * 选择子。
 * @author Jacky.Song
 */
public abstract class Selector {

	/**
	 * 编码选择子。
	 * <p>
	 * 顺序传入若干个字符串，这个方法可以计算那些字符串中有有效值(即不为null && 不为空)，
	 * 并返回一个数来代表那些字符串有有效值。
	 * <p>
	 * 字符串将按顺序，以2次幂编号，即第1个字符串编号1，第2个字符串编号2，第3个字符串编号4，
	 * 以此类推。返回值为 所有 有有效值的字符串的编号和。
	 * <p>
	 * 这样，就可以用一个值确定哪些字符串有有效值，这在判断用户的输入选择的时候非常有用。
	 * <p>
	 * 比如，如果有3个输入框供用户输入，需要判断用户填充了哪些输入框，通过这个方法处理对应
	 * 输入框的字段，即可知道用户填充了哪些输入框：<br/>
	 * 		3个输入框分别会被编号1,2,4——<br/>
	 * 		如果返回值=1，则用户只填充了第1个输入框(1=1+0+0)；如果返回值=3，则用户填充了
	 * 第1、2个输入框(3=1+2+0)；如果返回值=5，则用户填充了第1、3个输入框(5=1+0+4)<br/>
	 * ...以此类推，即可确定用户的输入选择。
	 * @see decodeSelector(int selectFieldNum,int selectorFlag)
	 * @param values 需要判断的值
	 * @return 选择子
	 */
	public static <T> int encodeSelector(Judgment<T> judge ,T... values) {
		int reValue=0;
		
		for (int i = 0; i < values.length; i++) {//遍历字段
			reValue +=//编码后马上累加到reValue
				judge.canPass(values[i]) ? 
						((i==0)?1:2<<(i-1)) ://如果判断通过，用2次幂编码(这里用移位操作来实现) 
						0;//否则编码为0
		}//遍历完毕即得到答案
		
		return reValue;
	}

	/**
	 * 和<code>encodeSelector()</code>方法配合使用，可以解码由此
	 * 方法产生的值，然后返回一个对应输入的boolean数组，如果某个输入被填写，则
	 * 对应的数组元素为true，否则为false。
	 * @see encodeSelector(int selectFieldNum,int selectorFlag)
	 * @param selectCount 参与判断的值的数量
	 * @param selector 按2次幂编码的选择子
	 * @return 结果数组
	 */
	public static boolean [] decodeSelector(int selectCount,int selector) {
		boolean [] reValue=new boolean[selectCount];
		
		for(int i=selectCount-1;i>=0;i--) {
			selector+=selector<0?//每次计算前先判断选择子的符号，如果<0，就要反过来加，否则永远不可能为正了
					1<<i://<0时，往正方向加
					-1<<i;//>0时，往负方向减
			
			reValue[i]=(selector>=0);//完成一次计算后，>0就是有，<0就是没有

			if(selector==0) {//=0表示完成了推算过程
				break;
				/*
				 * 注意，就算没有这句循环也会结束，只不过每次都要循环满selectFieldNum次，
				 * 而有些时候是不需要循环满都可以得到结果(即当selectorFlag某次计算后=0时)，
				 * 这样就不必继续计算了，利用Java初始化boolean数组的规则，这些未被赋值的元素
				 * 就是false，而它们的正确计算结果也就是false，所以可以不用傻乎乎的“计算一次，
				 * 得到false，再给它们赋值”了。
				 */
			}
		}
		
		return reValue;
	}

	
}
